home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Simple Slideshow / GIF.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-20  |  18.7 KB  |  544 lines  |  [TEXT/GEOL]

  1. /* *****************************************************************************
  2.     FILE:             GIF.c
  3.     
  4.     DESCRIPTION:     routine for reading in GIF files
  5.  
  6.    ***************************************************************************** */
  7.  
  8. #ifndef __COLOURLAB__
  9. #define    __COLOURLAB__
  10. #endif
  11.  
  12. #include     "GIF.h"
  13. //#include    "ColourLabWindows.h"
  14. //#include    "FloatingWindows.h"
  15. //#include    "WindowManagerMenu.h"
  16. //#include    "ImagePalette.h"
  17. #include    "Progress.h"
  18. #include    "BitMapUtils.h"
  19.  
  20. #include    <LowMem.h>
  21.  
  22. #ifndef    __powerc
  23.     #include    <Errors.h>
  24. #endif
  25.  
  26. //#define    USE_PROGRESS_DIALOG
  27.  
  28. short    gMessage;
  29.  
  30.  
  31.  
  32. #define ColorMapMask            0x80
  33. #define    ImageSeparator            0x2C
  34. #define    ExtensionIntroducer        0x21
  35. #define    NullBlock                0x00
  36. #define    InterlaceMask            0x40
  37. #define    BufferSize                8192                                    // May be freely modified
  38.  
  39. #define    abort(x)                { gMessage = x; goto end; }
  40. #define    Check(x)                if (e) abort(x)                            // this means return e
  41. #define    Read(c, buf)            count = c;                                                                    \
  42.                                 e = FSRead (refNum, &count, buf);        /* Read the requested number of bytes */    \
  43.                                 Check(strCantRead)                                                            \
  44.                                 FileSize -= count                        /* And note that we have read them */
  45.                         
  46. #define    NextByte(b)                Read(1, &b)
  47.  
  48. #define    Skip(n)                    e = SetFPos (refNum, fsFromMark, n);    /* Skip n bytes */                        \
  49.                                 Check(strCantSetFPos)                                                        \
  50.                                 FileSize -= n                            // And note that we have read them */
  51.  
  52. #define    FillBuffer                {                                                                        \
  53.     BufferPointer = BufferBase;                                                                            \
  54.     Read (BufferSize <= FileSize ? BufferSize : FileSize, BufferBase);                                                \
  55. }
  56.  
  57. #define    BufferGetOne            {                                                                        \
  58.     if (++BufferPointer >= BufferTop)                                /* If we are at the end of the buffer */        \
  59.         FillBuffer                                                    /* Then fill it again */                    \
  60.     if (BlockCount == 0) {                                            /* If the next byte is a length byte */        \
  61.         BlockCount = *(BufferPointer++);                            /* Then skip it and update BlockCount */        \
  62.         if (BufferPointer == BufferTop)                                /* If this brings us to the end of the buffer */    \
  63.             FillBuffer                                                /* Then fill it again */                    \
  64.     }                                                                                                \
  65.     BlockCount--;                                                                                        \
  66. }
  67.  
  68. #define    ReadCode(code)            {                                                                        \
  69.     if (BitOffset == 0) BufferGetOne                                                                        \
  70.     data = *BufferPointer;                                            /* Read the current byte */                \
  71.     newBitOffset = BitOffset + CodeSize;                                                                    \
  72.     if (newBitOffset > 8) {                                            /* If we need more, read the next byte */    \
  73.         BufferGetOne                                                                                    \
  74.         data += ((long) (*BufferPointer)) << 8;                                                                \
  75.     }                                                                                                \
  76.     if (newBitOffset > 16) {                                        /* If we still need more, read a third byte */    \
  77.         BufferGetOne                                                                                    \
  78.         data += ((long) (*BufferPointer)) << 16;                                                                \
  79.     }                                                                                                \
  80.     data >>= BitOffset;                                                /* Skip the bits we already processed */        \
  81.     BitOffset = newBitOffset & 7;                                    /* Compute the new bit offset */            \
  82.     code = data & ReadMask;                                            /* Mask off the bits we don't want yet */    \
  83. }
  84.  
  85. #ifdef USE_PROGRESS_DIALOG
  86. #define    DrawPixel(index)        {                                                                    \
  87.     * (Byte*) curAddr = index;                                        /* Write out the pixel */                    \
  88.     curAddr = (long *) ((Byte*) curAddr + 1);                        /* Update the pointer */                    \
  89.     if (++xc == Width) {                                            /* Update the x-coordinate */                \
  90.         xc = 0;                                                        /* If it overflows, update the y-coordinate */    \
  91.         if (!Interlaced)                                            /* In a non-interlaced picture, just */        \
  92.             yc++;                                                    /* increment yc to the next scan line */        \
  93.         else {                                                                                        \
  94.             switch (Pass) {                                            /* Otherwise deal with the interlace as */    \
  95.             case 0:                                                    /* described in the GIF spec */                \
  96.                 yc += 8;                                                                                \
  97.                 if (yc >= Height) {    Pass++;    yc = 4;    }                                                    \
  98.                 break;                                                                                \
  99.             case 1:                                                                                    \
  100.                 yc += 8;                                                                                \
  101.                 if (yc >= Height) {    Pass++;    yc = 2;    }                                                    \
  102.                 break;                                                                                \
  103.             case 2:                                                                                    \
  104.                 yc += 4;                                                                                \
  105.                 if (yc >= Height) {    Pass++;    yc = 1;    }                                                    \
  106.                 break;                                                                                \
  107.             case 3:                                                                                    \
  108.                 yc += 2;                                                                                \
  109.                 break;                                                                                \
  110.             default:                                                                                    \
  111.                 break;                                                                                \
  112.             }                                                                                        \
  113.         }                                                                                            \
  114.         curAddr = (long*) ((long) srcBaseAddr + (long) yc * (long) rowBytes);    /* update current address in bitmap */        \
  115.         \
  116.         /* $$GCOX- update progress bar*/\
  117.         \
  118.         SetGWorld(oldWorld,oldDevice);\
  119.         if (! ProgressUpdate(progRefNum,yc)) {\
  120.             e = userCanceledErr;    \
  121.             abort(e);    }\
  122.         SetGWorld(*world,NULL);\
  123.     }                                                                                                \
  124. }
  125. #else
  126. #define    DrawPixel(index)        {                                                                    \
  127.     * (Byte*) curAddr = index;                                        /* Write out the pixel */                    \
  128.     curAddr = (long *) ((Byte*) curAddr + 1);                        /* Update the pointer */                    \
  129.     if (++xc == Width) {                                            /* Update the x-coordinate */                \
  130.         xc = 0;                                                        /* If it overflows, update the y-coordinate */    \
  131.         if (!Interlaced)                                            /* In a non-interlaced picture, just */        \
  132.             yc++;                                                    /* increment yc to the next scan line */        \
  133.         else {                                                                                        \
  134.             switch (Pass) {                                            /* Otherwise deal with the interlace as */    \
  135.             case 0:                                                    /* described in the GIF spec */                \
  136.                 yc += 8;                                                                                \
  137.                 if (yc >= Height) {    Pass++;    yc = 4;    }                                                    \
  138.                 break;                                                                                \
  139.             case 1:                                                                                    \
  140.                 yc += 8;                                                                                \
  141.                 if (yc >= Height) {    Pass++;    yc = 2;    }                                                    \
  142.                 break;                                                                                \
  143.             case 2:                                                                                    \
  144.                 yc += 4;                                                                                \
  145.                 if (yc >= Height) {    Pass++;    yc = 1;    }                                                    \
  146.                 break;                                                                                \
  147.             case 3:                                                                                    \
  148.                 yc += 2;                                                                                \
  149.                 break;                                                                                \
  150.             default:                                                                                    \
  151.                 break;                                                                                \
  152.             }                                                                                        \
  153.         }                                                                                            \
  154.         curAddr = (long*) ((long) srcBaseAddr + (long) yc * (long) rowBytes);    /* update current address in bitmap */        \
  155.     }                                                                                                \
  156. }
  157. #endif
  158.  
  159. #define    ReadColorMap            {                                                                    \
  160.     Boolean        mapPresent;                                                                            \
  161.     CTabPtr        tablePtr;                                                                                \
  162.     short        i;                                                                                    \
  163.                                                                                                     \
  164.     mapPresent = (flags & ColorMapMask) ? true : false;                    /* Does the file have a global color map ? */    \
  165.     if (mapPresent) {                                                                                    \
  166.         BitsPerPixel = (flags & 7) + 1;                                    /* Image bit depth */                    \
  167.         ColorMapSize = 1 << BitsPerPixel;                                /* Number of entries in color table */        \
  168.         BitMask = ColorMapSize - 1;                                                                        \
  169.                                                                                                     \
  170.         if (ColorTable != NULL)                                            /* The local table overrides the global one */    \
  171.             DisposeHandle ((Handle) ColorTable);                        /* so let's get rid of the latter if it exists */    \
  172.         ColorTable = (CTabHandle) NewHandle (8*ColorMapSize+8);            /* Allocate memory for the table */        \
  173.         if (ColorTable == NULL) { e = memFullErr; abort(strGIFNoMem) }                                            \
  174.         HLock((Handle) ColorTable);                                                                        \
  175.         tablePtr = *ColorTable;                                                                            \
  176.         tablePtr->ctSeed = 0;                                            /* I don't know what to put in there */        \
  177.         tablePtr->ctFlags = 0;                                            /* so I just zero these fields */            \
  178.         tablePtr->ctSize = ColorMapSize - 1;                                                                \
  179.                                                                                                     \
  180.         for (i = 0; i < ColorMapSize; i++) {                                                                    \
  181.             tablePtr->ctTable[i].value = i;                                                                    \
  182.             NextByte(b);                                                                                \
  183.             tablePtr->ctTable[i].rgb.red = (short) b * 0x100;            /* Determine RGB value */                \
  184.             NextByte(b);                                                                                \
  185.             tablePtr->ctTable[i].rgb.green = (short) b * 0x100;                                                    \
  186.             NextByte(b);                                                                                \
  187.             tablePtr->ctTable[i].rgb.blue = (short) b * 0x100;                                                    \
  188.         }                                                                                            \
  189.         HUnlock((Handle) ColorTable);                                                                        \
  190.     }                                                                                                \
  191.     HasColorMap = HasColorMap || mapPresent;                                                                \
  192. }
  193.  
  194.  
  195. /************************************************************************
  196. ************************************************************************/
  197.  
  198. OSErr     ParseGIF(FSSpec *spec,GWorldPtr *world)
  199. {
  200.     OSErr            e;                                                /* Error code */
  201.     short            refNum;                                            /* File reference number */
  202.     long            sig;
  203.     long            count,FileSize;
  204.     Byte            b, flags, c;
  205.     short            BitsPerPixel, ColorMapSize, BitMask;
  206.     short            Width, Height;
  207.     short            ClearCode, FreeCode, EOFCode, FirstFree;
  208.     Byte            CodeSize, InitCodeSize;
  209.     short            MaxCode;
  210.     Byte            *BufferBase = NULL;                                /* Read buffer */
  211.     Byte            *BufferPointer, *BufferTop;                        /* Offset in buffer */
  212.     Byte            BlockCount;                                        /* Remaining bytes in current block */
  213.     Byte            BitOffset, newBitOffset;
  214.     long             data;
  215.     short            ReadMask;                                        /* Mask with exactly CodeSize bits set to 1 */
  216.     short            CurCode, InCode, OldCode, Code;                    /* Decompressor variables */
  217.     short            FinChar;
  218.     short            *OutCodeBase = NULL;                            /* Output array used by the decompressor */
  219.     short            *OutCode;                                        /* Current pointer into this array */
  220.     short            *Prefix = NULL;                                    /* The hash table used by the decompressor */
  221.     short            *Suffix = NULL;
  222.     short            xc, yc;                                            /* Pen position */
  223.     short            Pass;                                            /* Used by the output routines for interlaced pics */
  224.     Boolean            HasColorMap, Interlaced;
  225.     PixMapHandle    srcPixMap;                                        /* These are associated with 'world' */
  226.     long            *srcBaseAddr, *curAddr;                            /* Pixmap base address and current address */
  227.     short            rowBytes;
  228.     Rect            bounds;
  229.     CTabHandle        ColorTable = NULL;                                /* Custom color table */
  230.     GWorldPtr        oldWorld;                                        /* Some temporary variables */
  231.     GDHandle        oldDevice;
  232.     long            progRefNum = 0;                                    // progress bar ref number
  233.     
  234.     
  235.     if (e = FSpOpenDF (spec, fsRdPerm, &refNum))                    /* Open the file */
  236.         abort(strCantOpenData)
  237.  
  238.     if (!(OutCodeBase = (short*) NewPtr(2050)))        { e = MemError(); abort(strGIFNoMem) }
  239.     if (!(Prefix = (short*) NewPtr(8192)))            { e = MemError(); abort(strGIFNoMem) }
  240.     if (!(Suffix = (short*) NewPtr(8192)))            { e = MemError(); abort(strGIFNoMem) }
  241.     if (!(BufferBase = (Byte*) NewPtr(BufferSize)))    { e = MemError(); abort(strGIFNoMem) }
  242.     
  243.     // get the file size
  244.     
  245.     e = GetEOF(refNum,&FileSize);
  246.     
  247.     Read (4, &sig);                                                    /* Read the GIF signature */
  248.     if (sig != 'GIF8') { e = paramErr; abort(strInvalidGIFSig) }    /* and make sure it's correct */
  249.     Skip(6);                                                        /* Skip screen dimensions */
  250.     NextByte(flags);                                                /* This flag byte is processed below */
  251.     Skip(2);                                                        /* Skip background color and aspect ratio */
  252.     
  253.     ReadColorMap                                                    /* Read the global color map */
  254.  
  255.     while (TRUE)
  256.     {
  257.         NextByte(b);                                                /* Read the first byte of the block */
  258.         
  259.         switch (b)
  260.         {
  261.             case ImageSeparator:                                    /* Image separator, let's go read the image */
  262.                 goto ReadImage;
  263.             case ExtensionIntroducer:                                /* Extension block */
  264.                 Skip(1);                                            /* Skip the extension label */
  265.                 NextByte(b);                                        /* Get the block size */
  266.                 Skip(b);                                            /* Skip the block */
  267.                 
  268.                 NextByte(b);                                        /* Read the subsequent data blocks */
  269.                 while (b != NullBlock)
  270.                 {                                                    /* until a trailer block is reached */
  271.                     Skip(b);                                        /* Skip this block */
  272.                     NextByte(b);                                    /* Get length of the next block */
  273.                 }
  274.                 
  275.                 break;
  276.             default:                                                /* Unknown file format */
  277.                 e = paramErr;
  278.                 abort(strUnknownGIFBlock);
  279.         }
  280.     }
  281.  
  282. ReadImage:
  283.     Skip(4);                                                        /* Skip left and top offsets */
  284.     NextByte(b); NextByte(c);                                        /* Read width and height */
  285.     Width = (short) c * 0x100 + b;                                    /* Byte per byte because they are written */
  286.     NextByte(b); NextByte(c);                                        /* in stupid PC-like big-endian order */
  287.     Height = (short) c * 0x100 + b;
  288.     
  289.     // $$ GCOX- Add a progress bar. We use the height of the image as the max value and advance it every
  290.     // scan line
  291.     
  292.     #ifdef USE_PROGRESS_DIALOG
  293.     e = PutUpProgressDialog(&progRefNum,Height,NULL,kCancelType);
  294.     ProgressMessage(progRefNum,"\pOpening GIF™ File...");
  295.     SetProgressDelay(progRefNum,120);    // don't display for first 2 seconds
  296.     #endif
  297.     NextByte(flags);
  298.     Interlaced = (flags & InterlaceMask) ? true : false;            /* See if the image is interlaced */
  299.  
  300.     ReadColorMap                                                    /* If there is a local color map, read it */
  301.     
  302.     if (!HasColorMap) { e = paramErr; abort(strNoColorMap) }        /* Make sure we have at least one color map */
  303.     
  304.     GetGWorld(&oldWorld, &oldDevice);                                /* save the current world */
  305.     SetRect(&bounds, 0, 0, Width, Height);                            /* and create our own */
  306.     
  307.     (*ColorTable)->ctSeed = GetCTSeed();        // $$GPC- set some seed value rather than zero (in 7.5.3+, 
  308.                                                 // failure to do this will hang the system)
  309.     
  310.     if ( e = MakeSafeGWorld( world, &bounds, 8, ColorTable, TRUE) )
  311.         abort( strGIFNoMem )
  312.  
  313.     LockPixels(GetGWorldPixMap(*world));                            /* Lock the pixel map */
  314.     SetGWorld (*world, NULL);                                        /* activate it */
  315.  
  316.     NextByte(CodeSize);
  317.     ClearCode = (1 << CodeSize);
  318.     EOFCode = ClearCode + 1;
  319.     FreeCode = FirstFree = ClearCode + 2;
  320.     
  321.     CodeSize++;
  322.     InitCodeSize = CodeSize;
  323.     MaxCode = (1 << CodeSize);
  324.     ReadMask = MaxCode - 1;
  325.  
  326.     BlockCount = 0;                                                    /* We start at the beginning of a block */
  327.     BitOffset = 0;                                                    /* and at the beginning of a byte */
  328.     BufferPointer = BufferTop = BufferBase + BufferSize;            /* Force the buffer to be filled immediately */
  329.     
  330.     xc = yc = 0;
  331.     Pass = 0;
  332.  
  333.     srcPixMap = GetGWorldPixMap(*world);                            /* Get the pixmap */
  334.     rowBytes = (*srcPixMap)->rowBytes & 0x7FFF;                        /* get rowBytes */
  335.     curAddr = srcBaseAddr = (long*) GetPixBaseAddr (srcPixMap);        /* and the base address of the pixmap */
  336.     
  337.     ReadCode(Code);
  338.     while (Code != EOFCode)
  339.     {                            
  340.         if (Code == ClearCode)
  341.         {                                                            /* Clear code sets everything back to its */
  342.             CodeSize = InitCodeSize;                                /* initial value, then reads the subsequent code */
  343.             MaxCode = (1 << CodeSize);                                /* as uncompressed data. */
  344.             ReadMask = MaxCode - 1;
  345.             FreeCode = FirstFree;
  346.             ReadCode(Code);
  347.             CurCode = OldCode = Code;
  348.             FinChar = CurCode & BitMask;
  349.             DrawPixel(FinChar);
  350.         }
  351.         else
  352.         {                                                            /* If not Clear code, then must be data. */
  353.             CurCode = InCode = Code;                                /* Save same as CurCode and InCode */
  354.  
  355.             OutCode = OutCodeBase;
  356.             if (CurCode >= FreeCode)
  357.             {                                                        /* If >= FreeCode, not in the hash table yet */
  358.                 CurCode = OldCode;                                    /* repeat the last character decoded */
  359.                 *(OutCode++) = FinChar;
  360.             }
  361.             
  362.             while (CurCode > BitMask)
  363.             {                                                        /* Pursue the chain pointed to by CurCode */
  364.                 *(OutCode++) = Suffix[CurCode];                        /* through the hash table to its end */
  365.                 CurCode = Prefix[CurCode];                            /* the output queue */
  366.             }
  367.  
  368.             FinChar = CurCode & BitMask;                            /* The last code in the chain is treated as raw data. */
  369.             *OutCode = FinChar;
  370.                         
  371.             while (OutCode >= OutCodeBase)                            /* Now we put the data out */
  372.                 DrawPixel(*(OutCode--));                            /* It's been stacked LIFO, so deal with it that way */
  373.  
  374.             Prefix[FreeCode] = OldCode;                                /* Build the hash table on-the-fly */
  375.             Suffix[FreeCode] = FinChar;                                /* No table is stored in the file */
  376.             OldCode = InCode;
  377.             
  378.             if (++FreeCode >= MaxCode)                                /* Point to the next slot in the table */
  379.                 if (CodeSize < 12)
  380.                 {                                                    /* If we exceed the current MaxCode value */
  381.                     CodeSize++;                                        /* increment the code size unless it's already 12 */
  382.                     MaxCode *= 2;                                    /* If it is, do nothing; the next code better be */
  383.                     ReadMask = MaxCode - 1;                            /* Clear */
  384.                 }                                                
  385.         }
  386.  
  387.         ReadCode(Code);                                                /* Read the next code */
  388.     }
  389.     
  390.     UnlockPixels(GetGWorldPixMap(*world));                            /* Unlock the pixel map */
  391.     SetGWorld (oldWorld, oldDevice);                                /* restore the previous graphics world */
  392.     
  393.     e = noErr;
  394. end:
  395. #ifdef USE_PROGRESS_DIALOG
  396.     if (progRefNum)
  397.         TakeDownProgressDialog(progRefNum);
  398. #endif
  399.     if (ColorTable)                                                    /* We can destroy the CTable, NewGWorld */
  400.         DisposeHandle((Handle) ColorTable);                        
  401.             
  402.     if (BufferBase)
  403.         DisposePtr((Ptr) BufferBase);
  404.         
  405.     if (Suffix)
  406.         DisposePtr((Ptr) Suffix);
  407.         
  408.     if (Prefix)
  409.         DisposePtr((Ptr) Prefix);
  410.         
  411.     if (OutCodeBase)
  412.         DisposePtr((Ptr) OutCodeBase);
  413.         
  414.     (void) FSClose(refNum);
  415.  
  416.     return(e);
  417. }
  418.  
  419.  
  420. //*************************************************************************************************************************
  421.  
  422.  
  423. // This is the mid-level function to open GIF files, called from the main file dispatcher
  424.  
  425. #ifndef __COLOURLAB__
  426.  
  427.  
  428. OSErr    LLOpenGIFFile(FSSpec *fileSpec,WindowPtr theWindow)
  429. {
  430.     OSErr            theErr;
  431.     GWorldPtr        tempWorld = NULL,theImage;
  432.     t3DWindowHdl    t3DH;
  433.     Boolean            needNewWindow;
  434.     Rect            dummy,iFrame;
  435.     short            resRefNum;
  436.     
  437.     needNewWindow = (theWindow == NULL);
  438.     
  439.     theErr = ParseGIF(fileSpec,&tempWorld);
  440.     
  441.     if (theErr == noErr)
  442.     {
  443.         // we actually got the bloody thing! Now either open a new window or install the
  444.         // GWorld into the existing one. Open the resource fork so we can take advantage
  445.         // of any special window positioning resource
  446.         
  447.         if (needNewWindow)
  448.         {
  449.             resRefNum = FSpOpenResFile(fileSpec,fsCurPerm);
  450.             if (resRefNum != -1)
  451.                 UseResFile(resRefNum);
  452.  
  453.             SetRect(&dummy,0,0,0,0);    
  454.             theWindow = GetNew3DWindow(kSOWindowID,&dummy,-1,GetWindowInFront(userKind));
  455.             
  456.             // this creates a window without a GWorld (-1 passed as depth parameter)
  457.             
  458.             if (resRefNum != -1)
  459.                 CloseResFile(resRefNum);
  460.         }
  461.         
  462.         t3DH = GetWindowInfo(theWindow);
  463.         
  464.         if (t3DH)
  465.         {
  466.             theImage = GetMasterLayerImage(t3DH);
  467.             
  468.             if(!needNewWindow && theImage)
  469.                 DisposeGWorld(theImage);    // needed for revert, etc
  470.             
  471.             iFrame = (*GetGWorldPixMap(tempWorld))->bounds;
  472.             SetMasterLayerImage(t3DH,tempWorld);
  473.             
  474.             CalibrateScrollBars(t3DH);
  475.             SetImageMagnification(t3DH,100);
  476.             InstallWindowPalette(theWindow);
  477.             
  478.             SetWTitle(theWindow,fileSpec->name);
  479.             ShowFWWindow(theWindow);
  480.             SelectFWWindow(theWindow);
  481.             if (needNewWindow)
  482.                 RegisterNewWindow(gWMList,theWindow);
  483.             (*t3DH)->imageCameFromFile = TRUE;
  484.             (*t3DH)->imageFile = *fileSpec;
  485.             (*t3DH)->imageToBeSaved = FALSE;
  486.             (*t3DH)->imageType = 'GIFf';
  487.         }
  488.         else
  489.         {
  490.             theErr = -108;
  491.             DisposeGWorld(tempWorld);
  492.         }
  493.     }    
  494.     return(theErr);
  495. }
  496.  
  497.  
  498. #endif
  499.  
  500.  
  501.  
  502. OSErr    ConvertGIFtoPICT(FSSpec *theFile,PicHandle *thePicture)
  503. {
  504.     // converts an open GIF file to a picture- used to create a preview image for the file, amongst other
  505.     // possible uses
  506.     
  507.     OSErr            theErr;
  508.     GWorldPtr        tempWorld;
  509.     CGrafPtr        savePort;
  510.     GDHandle        saveDevice;
  511.     PixMapHandle    gifPixels;
  512.     PicHandle        thePic;
  513.     Rect            picRect;
  514.  
  515.     theErr = ParseGIF(theFile,&tempWorld);
  516.     
  517.     if (theErr == noErr)
  518.     {
  519.         GetGWorld(&savePort,&saveDevice);
  520.         SetGWorld(tempWorld,NULL);
  521.         
  522.         gifPixels = GetGWorldPixMap(tempWorld);
  523.         picRect = (*gifPixels)->bounds;
  524.         
  525.         thePic = OpenPicture(&picRect);
  526.         ClipRect(&picRect);
  527.         if (LockPixels(gifPixels))
  528.         {
  529.             CopyBits((BitMap*)*gifPixels,(BitMap*)*gifPixels,&picRect,&picRect,srcCopy,NULL);
  530.             UnlockPixels(gifPixels);
  531.         }
  532.         ClosePicture();
  533.         
  534.         SetGWorld(savePort,saveDevice);
  535.         DisposeGWorld(tempWorld);
  536.         
  537.         picRect = (*thePic)->picFrame;
  538.         if (EmptyRect(&picRect))
  539.             theErr = memFullErr;    // picture creation failed
  540.         
  541.         *thePicture = thePic;
  542.     }
  543.     return(theErr);
  544. }